<?
// $Id: boot.php 88 2011-02-10 22:58:44Z MartinS $
// Initializes bot and defines variables

session_start();

error_reporting(E_ALL);

ini_set ("user_agent", "taxobot; verisimilus@toolserver.org");
define ("wikiroot", "http://en.wikipedia.org/w/index.php?");

//Common replacements
$pcDecode = array("[",                  "]",                    "<",                    ">");
$pcEncode = array("&#x5B;", "&#x5D;", "&#60;",  "&#62;");

$dotEncode = array(".2F", ".5B", ".7B", ".7D", ".5D", ".3C", ".3E", ".3B", ".28", ".29");
$dotDecode = array("/", "[", "{", "}", "]", "<", ">", ";", "(", ")");

// Taxonomic ranks that may appear in taxoboxes
$taxonomic_ranks = array_reverse(Array (
 "virus_group",
 "superdomain",
 "unranked_superdomain",
 "domain",
 "unranked_regnum",
 "superregnum",
 "regnum",
 "subregnum",
 "unranked_phylum",
 "superdivisio",
 "superphylum",
 "divisio",
 "unranked_divisio",
 "phylum",
 "subdivisio",
 "subphylum",
 "infraphylum",
 "microphylum",
 "nanophylum",
 "unranked_classis",
 "superclassis",
 "classis",
 "subclassis",
 "infraclassis",
 "unranked_ordo",
 "magnordo",
 "superordo",
 "ordo",
 "subordo",
 "infraordo",
 "parvordo",
 "zoodivisio",
 "zoosectio",
 "zoosubsectio",
 "unranked_familia",
 "superfamilia",
 "familia",
 "subfamilia",
 "unranked_tribus",
 "supertribus",
 "tribus",
 "subtribus",
 "unranked_genus",
 "genus",
 "subgenus",
 "sectio",
 "series",
 "species_group",
 "species_subgroup",
 "species_complex",
 "species",
 "subspecies",
));

$major_ranks = array_reverse(Array (
  "virus_group",
  "regnum",
  "phylum",
  "divisio",
  "classis",
  "ordo",
  "familia",
  "genus",
  "species",
));

if ($html_output > 0) { ?>
<!DOCTYPE html>
<html lang="en" dir="ltr">
	<head>
		<meta charset="utf-8" />
    <meta content="Smith609" name="author">

		<link rel="apple-touch-icon" href="http://en.wikipedia.org/apple-touch-icon.png" />
		<link rel="copyright" href="http://www.gnu.org/copyleft/fdl.html" />
		<title>Taxobot - Wikipedia taxonomy assistant</title>

  <style type="text/css" media="screen,projection">
    /*
    <![CDATA[*/ @import "/~luxo/skins/toolserver/main.css?67"; /*]]>
    */
  input, label, .infobox {float:right}
  p.row {clear:both}
  /* copied from WP->index.php*/
  .infobox {
    border: 1px solid #aaa;
    background-color: #f9f9f9;
    color: black;
    margin: 0.5em 0 0.5em 1em;
    padding: 0.2em;
    float: right;
    clear: right;
  }
  .infobox td,
  .infobox th {
      vertical-align: top;
  }
  .infobox caption {
      font-size: larger;
  }
  .infobox.bordered {
      border-collapse: collapse;
  }

  </style>
	</head><?
}


function includeIfNew($file){
        // include missing files
        $alreadyIn = get_included_files();
        foreach ($alreadyIn as $include){
                if (strstr($include, $file)) return false;
        }
        if ($GLOBALS["linkto2"]) echo "\n// including $file";
        include($file . $GLOBALS["linkto2"] . ".php");
        return true;
}

function revisionID() {
    global $last_revision_id;
    if ($last_revision_id) return $last_revision_id;
    $svnid = '$Rev: 88 $';
    $scid = substr($svnid, 6);
    $thisRevId = intval(substr($scid, 0, strlen($scid) - 2));
    return $thisRevId;
    $repos_handle = svn_repos_open('~/taxobot');
    return svn_fs_youngest_rev($repos_handle);
}

if ($html_output > 0) {
  echo " \n Getting login details ... ";
}
require_once("/home/verisimilus/public_html/Bot/taxobot/taxobot$linkto2.login");
if ($html_output > 0) {
  echo " done.";
}
# Snoopy should be set so the host name is en.wikipedia.org.
include("inc/accept_arguments.php");
includeIfNew('Snoopy.class');
includeIfNew('linkWikiFunctions'); // This is a symbolic link to ~/citation-bot/wikiFunctions.php

/*echo "\n Connecting to MYSQL database ... ";
require_once("/home/verisimilus/public_html/res/mysql_connect.php");
$db = udbconnect("yarrow");
echo " connected.";*/
$bot = new Snoopy();

mb_internal_encoding( 'UTF-8' ); // Avoid ??s

define("debugon", $_GET["debug"]);
define("editinterval", 10);
define("api", "http://en.wikipedia.org/w/api.php");

//Optimisation
#ob_start(); //Faster, but output is saved until page finshed.
#ini_set("memory_limit", "256M");
#die(":::0");
$user = $_REQUEST["user"];
if ($_REQUEST["edit"]) {
  $ON = true;
}

$editSummaryStart = ($bugFix?"Double-checking that a [[User:taxobot/bugs|bug]] has been fixed. ":"Taxonomy: ");
ob_flush();

################ Functions ##############

// This function is called from the end of this page.
function logIn($username, $password) {
    global $bot; // Snoopy class loaded elsewhere

  // Set POST variables to retrieve a token
        $submit_vars["format"] = "json";
        $submit_vars["action"] = "login";
        $submit_vars["lgname"] = $username;
        $submit_vars["lgpassword"] = $password;
        // Submit POST variables and retrieve a token
  $bot->submit(api, $submit_vars);
  $first_response = json_decode($bot->results);
  $submit_vars["lgtoken"] = $first_response->login->token;
  // Store cookies; resubmit with new request (which hast token added to post vars)
  foreach ($bot->headers as $header) {
    if (substr($header, 0,10) == "Set-Cookie") {
      $cookies = explode(";", substr($header, 12));
      foreach ($cookies as $oCook) {
        $cookie = explode("=", $oCook);
        $bot->cookies[trim($cookie[0])] = $cookie[1];
      }
    }
  }

  $bot->submit(api, $submit_vars);
  $login_result = json_decode($bot->results);
  if ($login_result->login->result == "Success") {
    if ($html_output > 0 ) echo "\n Using account " . $login_result->login->lgusername . ".";
    // Add other cookies, which are necessary to remain logged in.
    $cookie_prefix = "enwiki";
    $bot->cookies[$cookie_prefix . "UserName"] = $login_result->login->lgusername;
    $bot->cookies[$cookie_prefix . "UserID"] = $login_result->login->lguserid;
    $bot->cookies[$cookie_prefix . "Token"] = $login_result->login->lgtoken;
    return true;
  } else {
    die( "\nCould not log in to Wikipedia servers.  Edits will not be committed.\n" . print_r($login_result, 1)); // Will not display to user
    global $ON; $ON = false;
    return false;
  }
}

function development_mode() {
  return (strpos($_SERVER["REQUEST_URI"], "_dev") ? true : false);
}

function pre($text, $p1, $p2, $p3) {
  if (development_mode()) {
    print "<pre>" . (is_array($text) ? print_r($text, 1) : $text) .
            (is_array($p1) ? print_r($p1, 1) : $p1) .
            (is_array($p2) ? print_r($p2, 1) : $p2) .
            (is_array($p3) ? print_r($p3, 1) : $p3) . "</pre>";
  }
}

function upgrade_button($taxon, $taxobox = null, $automatic_taxobox = null) {
  $content = getRawWikiText($taxon["link"]);
  if (true || !$taxobox) { // TODO
    $taxobox = extract_template($content, "taxobox");
    $automatic_taxobox = automate_taxobox($taxobox, $taxon["link"]);
  }
  return "\n<li style='margin-bottom:1em;border-bottom:1px dotted black;'>" . $taxon["rank"] . ": "
              . wikiLink($taxon["link"], false, $taxon["taxon"])
              . "<form action=\"http://en.wikipedia.org/w/index.php?action=submit&title=" . urlencode($taxon["link"])
              . "\" name=editform method=post enctype=\"multipart/form-data\">"
              . "<textarea style=\"display:block; width:100px; height:100px;\" name=\"wpTextbox1\">"
              . str_replace($taxobox, $automatic_taxobox, $content)
              . "</textarea>"
              . "<input type=submit name=wpPreview value='Show preview' />"
              . "<input type=hidden id=wpSummary value='Upgrade to automatic taxobox using [[User:Taxobot]]' />"
              . "</form></li>";
}

function write($page, $data, $edit_summary = "Bot edit") {

  global $bot;

  // Check that bot is logged in:
  $bot->fetch(api . "?action=query&prop=info&meta=userinfo&format=json");
  $result = json_decode($bot->results);

  if ($result->query->userinfo->id == 0) {
    return "LOGGED OUT:  The bot has been logged out from Wikipedia servers";
  }

  $bot->fetch(api . "?action=query&prop=info&format=json&intoken=edit&titles=" . urlencode($page));
  $result = json_decode($bot->results);

  foreach ($result->query->pages as $i_page) {
    $my_page = $i_page;
  }

  $submit_vars = array (
    "action"    => "edit",
    "title"     => $my_page->title,
    "text"      => $data,
    "token"     => $my_page->edittoken,
    "summary"   => $edit_summary,
    "minor"     => "1",
    "bot"       => "1",
    #"basetimestamp" => $my_page->touched,
    #"starttimestamp" => $my_page->starttimestamp,
    #"md5"       => md5($data),
    "watchlist" => "nochange",
    "format"    => "json",
  );

  $bot->submit(api, $submit_vars);
  $result = json_decode($bot->results);

  if ($result->edit->result == "Success") {
    // Need to check for this string whereever our behaviour is dependant on the success or failure of the write operation
    return "Success";
  } else if ($result->edit->result) {
    return $result->edit->result;
  } else if ($result->error->code) {
    // Return error code
    return strtoupper($result->error->code) . ": " . str_replace(array("You ", " have "), array("This bot ", " has "), $result->error->info);
  } else {
    return "Unhandled error.  Please copy this output and <a href=http://code.google.com/p/citation-bot/issues/list>report a bug.</a>";
  }
}

if (!$html_output) {
  echo "\n Establishing connection to Wikipedia servers ... ";
}
// Log in to Wikipedia
logIn(USERNAME, PASSWORD);

/*
echo "\n Fetching parameter list ... ";
// Get a current list of parameters used in citations from WP
$page = $bot->fetch(api . "?action=query&prop=revisions&rvprop=content&titles=User:Citation_bot/parameters&format=json");
$json = json_decode($bot->results, true);
$parameter_list = (explode("\n", $json["query"]["pages"][26899494]["revisions"][0]["*"]));
*/
if (!$html_output) {
  echo "\n boot.php complete.";
}

function javascript_ranks() {
  global $taxonomic_ranks;
  print "<script type='text/javascript'>taxonomicRanks = {";
  foreach ($taxonomic_ranks as $rank) {
    print "'$rank':'',";
  }
  print "'clade':'', 'informal group':'', 'cohort':'', 'unranked':''};</script>";
}


// Convert list of species to use {{linked species list}} or {{species list}}.
function species_list($list, $template = "species") {

  # TODO: nested species list,as at Acariformes
  if (preg_match("~\bsee\b~i", $list)) {
    // Don't template "See text", for instance
    return $list;
  }
  $ref_regexp = "~<ref[\s\S]*?</ref>"  // References 
              . "|" . "\{\{(?:[^\}]|\}[^\}])*\}\}" // Templates
              . "~";
  if (preg_match_all($ref_regexp, $list, $removed_references)) {
    $list = preg_replace($ref_regexp, "!REFPLACEHOLDER!", $list);
    $iR = 0;
  }
  $lines = explode("\n", $list);
  foreach ($lines as $line) {
    if (preg_match("~!REFPLACEHOLDER!~", $line, $ref_match)) {
      // ToDo: Replacement of multiple per line, see Asteraceae
      $line = preg_replace("~!REFPLACEHOLDER!~", "", $line);
      $restore_references = true;
    } else {
      $restore_references = false;
    }
    //$line = str_replace("|", "{{!}}", $line);
    if (   preg_match("~'+'(?:&nbsp;)?(.+)''+(.*?)(?:<br */?>)?$~", $line, $match)
        || preg_match("~(.*)<small>(.*)</small>~", $line, $match)) {
      $new_list .= "|". preg_replace("~^[\s:\*]*(?:&nbsp;)*|\s*(?:<br */?>)?\s*$~", "", $match[1]) . "|"
                . ( $match[2] ? $match[2] : get_taxon_authority(preg_replace("~<br */?>|[^\w\s]~", "", $match[1]) ) )
                . ($restore_references ? $removed_references[0][$iR++] : "") . "\n";
    } elseif (trim($line) != "") {
      $new_list .= "  |" . preg_replace("~^[\*:](?:\s|&nbsp;)*|\s*(?:<br */?>)?\s*$~", "", $line)
                .  "  |" . get_taxon_authority(preg_replace("~<br */?>|[^\w\s]~", "", $line)) 
                . ($restore_references ? $removed_references[0][$iR++] : "") . "\n";
      // TODO: replace A. baconi with Ailuropoda baconi for the search; see [[Ailuropoda]].
    }
  }
  return '{{' . $template . " list \n"
            . $new_list
            . "  }}\n";
}


function get_taxon_authority ($taxon) {
  $taxon = trim($taxon);
  $taxon_details = json_decode(file_get_contents("http://gni.globalnames.org/name_strings.json?search_term=ns:$taxon"));
  $taxon_id = $taxon_details->name_strings[0]->id;
  print "\n[http://gni.globalnames.org/name_strings.json?search_term=ns:$taxon]\n";
  $lexicon = file_get_contents("http://gni.globalnames.org/name_strings/$taxon_id");
  if (preg_match_all("~(\d+)\">" . preg_quote($taxon) . "\s+([\p{L}\p{M}\- ]*, \d{4})</a>~", $lexicon, $match)) {
    $matched = true;
  } elseif (preg_match_all("~(\d+)\">" . preg_quote($taxon) . "\s+([\p{L}\p{M}\- ]*, \d{4})</a>~", utf8_decode($lexicon), $match)) {
    $matched = true;
    $utf8_encoded = true;
  }
  if ($matched) {
    if ($match[0][1]) {
      $return_string = "<!-- There are multiple authorities for this taxon; please select the correct one:\n ";
      foreach($match[1] as $i => $id) {
        $further_details = file_get_contents("http://gni.globalnames.org/name_strings/$id");
        if (preg_match("~ href=\"([^\"]+)\">\d+ record~", $further_details, $url_match)) {
          $match[3][$i] = $url_match[1];
        }
      }
      foreach ($match[2] as $i => $auth) {
        $return_string .= "$auth" . ($match[3][$i] ? " (see {$match[3][$i]} )" : "") . "\n ";
      }
      return $return_string . "-->[[Category:Taxa with ambiguous authority information]]";
    } else {
      $expected_authority = $utf8_encoded ? utf8_encode($match[2][0]) : $match[2][0];
      $authed_taxon_id = $match[1][0];
      $authed_taxon_details = file_get_contents("http://gni.globalnames.org/name_strings/$authed_taxon_id");
      if (strpos($authed_taxon_details, ">authorship: </span>$expected_authority")) {
        return $expected_authority;
      } else {
        return "<!-- $expected_authority (automatically generated, please check) -->";
      }
    }
  } else {
    return "<!-- Missing authority information -->";
  }
}

// Remove any errors generated by reference templates, etc, whilst making links absolute
function rm_errormsg($txt) {
  return trim(
         preg_replace("~\"/(w[ik]*)/~", '"http://en.wikipedia.org/$1/',
         preg_replace("~<!--[^>]*-->~", '',
         preg_replace("~<div style=\"display:none;.*</div>~", '',
         preg_replace("~<strong class=\"error\"[\s\S]*</strong>~", "", $txt)))));
}


// Attempt to convert a fossil range to use {{fossil range|}}.
function fossilize($range) {
  $rng = trim(str_replace(array("[[", "]]", "|"), Array("", "", "{{!}}"), $range));
  if (preg_match("~<ref.*>~", $rng, $match)) {
    $rng = str_replace($match, "", $rng);
    $refs = "|ref=$match";
  }
  $dash_regexp = "~\s*(-| to |&ndash;)~"; // TODO add ndash unicode code
  if (preg_match($dash_regexp, $rng, $match)) {
    $range_limits = explode($match[0], $rng);
    $range_end = trim(preg_replace("~my?a|million years ago\s*$~", "", $range_limits[1]));
    $template = '{{Geological range|' . trim($range_limits[0]) . "|" . $range_end . ($refs?$refs:"") . '}}';
    return geo_range_ok($template)?$template:$range;
  }
  else if (!strpos($range, " ")) {
    $template = '{{' . "Geological range|$rng" . ($refs ? $refs : "") . '}}';
    return geo_range_ok($template)?$template:$range;
  } else {
    return $range;
  }
}

function automate_taxobox ($taxobox, $page_name, $simple = false, $no_edit = false) {
  global $taxonomic_ranks, $major_ranks;
  $p = extract_parameters($taxobox);
  
  foreach ($p as $key => $value) {
    if ($value[0]) {
      if (!in_array($key, $taxonomic_ranks)) {
        if (substr($key, -10) == "_authority") {
          $authorities[$key] = $value;
        } else {
          switch ($key) {
            case "name": //drop if unnecessary
              if ($value[0] != $page_name) {
                $out[$key] = $value;
              }
              break;
            case "fossil_range":
              $out[$key] = $simple ? $value : array(fossilize($value[0]), $value[1], $value[2]);
              break;
            case "subdivision":
              $out[$key] = $simple ? $value : array(species_list($value[0], preg_match("~species|genus|genera~i", $p["subdivision_ranks"][0])?"species":"taxon"), $value[1], $value[2]);
              break;
            case "synonyms":
              $out[$key] = $simple ? $value : array(species_list($value[0], preg_match("~species|genus|genera|familia|family|families~i", $p["subdivision_ranks"][0])?"species":"taxon"), $value[1], $value[2]);
              break;
            case "subdivision_ranks": // TODO eventually: work out whether the parameter is redundnat
              $out[$key] = $value;
              break;
            case "":
            default:
              $out[$key] = $value;
          }
        }
      } else {
        // ELSE it's a taxon and we can drop the parameter
        $lowest_rank = $value[0];
        $taxa_parsed++;
        if (!$first_minor_taxon && !in_array($key, $major_ranks)) {
          $first_minor_taxon = $taxa_parsed;
        }
        // TODO: Expand F. genusname to Full genusname, e.g.  Bowhead_whale
        // TODO: Make a note of inferior ranks so that display_taxa can be set; see Baltoceratidae
      }
    }
  }
  if ($no_edit) {
    $out["edit link"] = array("", "\n | ", "=");
  }
  if ($taxa_parsed - $first_minor_taxon > 1) {
    $out["display_taxa"] = array($taxa_parsed - $first_minor_taxon, "\n | ", " = ");
  }
  $lowest_rank = str_replace(array("'", "[", "]"), "", $lowest_rank);
  if ($lowest_rank && strtolower($lowest_rank) != strtolower($page_name)) {
    $out = array_merge(array("taxon" => array ($lowest_rank, "\n | ", " = ")), $out);
  } 
  foreach ($taxonomic_ranks as $rank) {
    if ($authorities[$rank . "_authority"]) {
      $authority = $authorities[$rank . "_authority"][0];
      // Insert comma before year, if absent
      // Seems to remove, rather than add, a comma! -- See old revision of Epiprocta, 30 Nov 2010
      #$authority = preg_replace("~([\w\]])\s*( \d{4})~", "$1,$2", $authority);

      $out[ ($out["greatgrandparent_authority"]?"great":"")
          . ($out["grandparent_authority"]?"great":"")
          . ($out["parent_authority"]?"grand":"")
          . ($out["authority"]?"parent_":"")
          . "authority" ] = Array($authority, $authorities[$rank . "_authority"][1], $authorities[$rank . "_authority"][2]);
    }
  }
  if (!$simple && $p["authority"][0] == "") {
    $p["authority"][0] = get_taxon_authority($p["taxon"][0] ? $p["taxon"][0]
                                            : $lowest_rank ? $lowest_rank
                                            : $page_name);
  }
  
  return generate_template("automatic taxobox", $out);
}


function avoid_errors_flagging(){?><html><div><div><div><?}
function print_footer() {
 ?><footer>

						<!-- end content -->
			<div class="visualClear"></div>
		</footer>
	</div>
		</div>
		<div id="column-one">
	<div id="p-cactions" class="portlet">
		<h5>Views</h5>

		<div class="pBody">
			<ul>
					 <li id="ca-nstab-user" class="selected"><a href="http://en.wikipedia.org/wiki/User:Taxobot" title="View the user page [c]" accesskey="c">User page</a></li>
					 <li id="ca-talk" class="new"><a href="http://en.wikipedia.org/w/index.php?title=User_talk:Taxobot" title="Discussion about the content page [t]" accesskey="t">Discussion</a></li>
					 <li id="ca-edit"><a href="http://en.wikipedia.org/w/index.php?title=User_talk:Taxobot" title="Click here to report an error [e]" accesskey="e">Report error</a></li>
					 <li id="ca-history"><a href="http://en.wikipedia.org/wiki/Special:Contributions/Taxobot" title="This bot's contributions [x]" accesskey="x">Contributions</a></li>
				</ul>
		</div>
	</div>
	<div class="portlet" id="p-logo">
		<a style="background-image: url(http://wiki.ts.wikimedia.org/images/wiki-en.png);" ></a>
	</div>
	<script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script>
		</div><!-- end of the left (by default at least) column -->
			<div class="visualClear"></div>
			<footer>
				<div id="f-poweredbyico"><a href="http://wiki.ts.wikimedia.org/view/Main_Page"><img src="http://tools.wikimedia.de/images/wikimedia-toolserver-button.png" alt="Powered by Toolserver" /></a></div>
			<ul id="f-list">
				<li id="copyright">All text is available under the terms of the <a class='internal' href="http://en.wikipedia.org/wiki/Wikipedia:Text_of_the_GNU_Free_Documentation_License" title="Wikipedia:Text of the GNU Free Documentation License">GNU Free Documentation License</a>. (See <b><a class='internal' href="http://en.wikipedia.org/wiki/Wikipedia:Copyrights" title="Wikipedia:Copyrights">Copyrights</a></b> for details.)</li>
			</ul>
		</footer>
</div>
</body>
</html><?}?>